<?php
/**
 * Library for simplify creating of a WordPress plug-ins.
 * 
 * @author Ondrej Donek <ondrejd@gmail.com>
 * @copyright Copyright (c) 2010, Ondrej Donek
 * @license http://www.mozilla.org/license/ Mozilla Public License 1.0
 * @version ##VERSION##
 * @package odWpPlugin
 * 
 * @todo Create and implement odWpPlugin_Public_Renderer!
 */

/**#@+
 * Constants
 */
/**
 * Full path to the odWpPlugin source file.
 */
(!defined('ODWPPLUGIN_PATH')) || 
		define('ODWPPLUGIN_PATH', realpath(dirname(__FILE__)));
/**
 * Full path to the odWpPlugin localizations files.
 */
(!defined('ODWPPLUGIN_I18N_PATH')) ||
		define('ODWPPLUGIN_I18N_PATH', realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'i18n'));

/**
 * Are running PHPUnit tests?
 */
(!defined('IS_UNITTESTING')) || define('IS_UNITTESTING', false);
/**#@-*/

#{{{ Initialize WordPress localization ---
if(!function_exists('__')):
  /**
   * This is helper function for those cases the WP localization functions are
   * not present.
   *
   * @ignore
   * @param string $aStr
   * @return string
   */
  function __($aStr) {
    return $aStr;
  }
endif;
#}}} --- Initialize WordPress localization

// Initialize locales of odWpPlugin self
if(function_exists('load_plugin_textdomain')) {
  load_plugin_textdomain('odWpPlugin', ODWPPLUGIN_I18N_PATH);
}

#{{{ odWpPlugin ---
if(!class_exists('odWpPlugin')):

/**
 * Parent class for single WordPress plugins.
 * 
 * @package odWpPlugin
 * @author Ondrej Donek <ondrejd@gmail.com>
 */
class odWpPlugin
{
  /**
   * Holds version of odWpPlugin self.
   * 
   * @var string
   */
  const VERSION = '##VERSION##';
	
	/**
	 * Hold's ID of a plugin.
	 *
	 * @var string
	 */
	protected $mId;
	
	/**
	 * Hold's plugin name.
	 *
	 * @var string
	 */
	protected $mName;
	
	/**
	 * Hold's name of class that implements plugin.
	 *
	 * @var string
	 */
	protected $mClassname;
	
	/**
	 * Hold's plugin version.
	 *
	 * @var string
	 */
	protected $mVersion;
	
	/**
	 * Plugin's options.
	 *
	 * @var array
	 */
	protected $mOptions = false;
	
  /** 
   * Instance of plugin's renderer.
   * 
   * @var odWpPlugin_Admin_Renderer
   */
  protected $mAdminRenderer = null;
	
  
  /**
   * Constructor.
   * 
   * @param array $aOptions
   * @return void
   */
  public function __construct($aOptions = array())
  {
    // Base plugin properties
		$this->mId = $aOptions['id'];
		$this->mName = $aOptions['name'];
		$this->mClassname = $aOptions['classname'];
		$this->mVersion = $aOptions['version'];
    
		// Locales
		if(array_key_exists('localized', $aOptions)) {
      if($aOptions['localized'] === true) {
				load_plugin_textdomain($this->mClassname, self::getPath());
			}
		}
		
		// Options
		if(array_key_exists('options', $aOptions)) {
			if(is_array($aOptions['options'])) {
				$this->mOptions = $aOptions['options'];
			}
		}
		
		// Administration
    if(array_key_exists('admin', $aOptions)) {
      if($aOptions['admin'] === true || is_array($aOptions['admin'])) {
        $admin_options = array(
            'plugin_id' => $this->mId,
            'plugin_name' => $this->mName, 
            'plugin_classname' => $this->mClassname,
            'plugin_version' => $this->mVersion
        );
        
        if(is_array($aOptions['admin'])) {
          $admin_options = array_merge($admin_options, $aOptions['admin']);
        }
        
        $this->mAdminRenderer = new odWpPlugin_Admin_Renderer($admin_options);
      }
    }
		
		// Ensure that plugin's options are initialized
		$options = $this->initOptions();
		
		// Activation/deactivation
		register_activation_hook(__FILE__, array(&$this, 'activate'));
		register_deactivation_hook(__FILE__, array(&$this, 'deactivate'));
  } // end __construct($aOptions)
	
  
	/**
	 * Activates the plugin
	 * 
	 * @return void
	 */
	public function activate()
	{
    // Collect plugins metric data
		$this->collectMetricsData(
        $this->getId(), 
        $this->getName() . ' ' . $this->getVersion(), 
        get_bloginfo('home'), 
        'activate'
    );
	} // end activate()
  
  
	/**
	 * Deactivates the plugin
	 * 
	 * @return void
	 */
	public function deactivate()
	{
		// Collect plugins metric data
		$this->collectMetricsData(
        $this->getId(), 
        $this->getName() . ' ' . $this->getVersion(), 
        get_bloginfo('home'), 
        'deactivate'
    );
	} // end deactivate()
  
  
  /**
   * Returns name of class that implements of the plug-in.
   * 
   * @return string
   */
  public function getClassname() 
  {
    return $this->mClassname;
  } // end getClassname()
  
  
  /**
   * Returns ID of the plug-in.
   * 
   * @return string
   */
  public function getId() 
  {
    return $this->mId;
  } // end getId()
  

  /**
   * Returns full path to the directory with plugin's localization files.
   *
   * @return string
   */
  public function getI18nPath()
  {
    return $this->getPath() . DIRECTORY_SEPARATOR . 'i18n';
  } // end getI18nPath()
  
	
	/**
	 * Get plugin options.
	 * 
	 * @return array
	 */
	public function getOptions()
	{
		$options_id = $this->mId . '-options';
		return get_option($options_id);
	} // end getOptions()
  
  
  /**
   * Returns full path to the plugin's directory.
   * 
   * @return string
   */
  public function getPath()
  {
    return realpath(dirname(__FILE__));
  }

  /**
   * Returns full path to the plugin resources directory.
   * 
   * @return string
   */
  public function getResourcesPath()
  {
    return $this->getPath() . DIRECTORY_SEPARATOR . 'resources';
  }
  
  /**
   * Returns version of the plug-in.
   * 
   * @return string
   */
  public function getVersion() 
  {
    return $this->mVersion;
  } // end getVersion()
  
  
	/**
	 * Initialize plugin options (defaulty are options always initialized -
	 * if plugin doesn't contains own default options the only one registered
	 * value is version of the plugin).
	 * 
	 * @return array
	 */
	protected function initOptions() 
	{
		$options = $this->getOptions();
		$need_update = false;

		if($options === false) {
			$need_update = true;
			$options = array();
		}
    
    if(is_array($this->mOptions)) {
      foreach($this->mOptions as $key => $value) {
        if(!array_key_exists($key, $options)) {
          $options[$key] = $value;
        }
      }
    }

		if(!array_key_exists('latest_used_version', $options)) {
			$options['latest_used_version'] = $this->mVersion;
			$need_update = true;
		}

		if($need_update === true) {
			update_option($this->mId . '-options', $options);
		}

		return $options;
	} // end initOptions()
  
  
  /**
   * Insert given user roles into the WordPress environment. 
   * 
   * <code>
   * <?php
   * $aRoles = array(
   *   'role_1' => array('name' => 'Role 1', 'capabilities' => array(...)),
   *   'role_2' => array('name' => 'Role 2', 'capabilities' => array(...))
   * );
   * ?>
   * </code>
   * 
   * For capabilities of WordPress original user roles see the WP documentation.
   * 
   * @param array $aRoles Roles that you want to add into the WordPress.
   * @return void
   */
  protected function updateWpUserRoles($aRoles = array()) 
  {
    $user_roles = get_option('wp_user_roles');
    $need_update = false;
    
    if($user_roles === false) {
      wp_die('An error occured - common WordPress user roles are not defined!');
      return;
    }
    
    foreach($aRoles as $role_id => $role_vals) {
      $user_roles[$role_id] = $role_vals;
    }
    
    update_option('wp_user_roles', $user_roles);
  }
  
  /**
   * Collects metric data about my plugins.
   * 
   * @since 0.2
   * @param string $aPluginName
   * @param string $aPluginVersion
   * @param string $aSite
   * @param string $aAction
   * @return void
   */
  protected function collectMetricsData($aSite, $aAction)
  {
    global $wp_version;
    
    $url = parse_url(
      'http://www.ondrejd.info/od-wp-plugins-metric-data/index.php?' . 
      'name=' . $this->mName . '&' . 
      'version=' . $this->mVersion . '&' . 
      'site=' . $aSite . '&' . 
      'action=' . $aAction . '&' . 
      'wp_version=' . $wp_version
    );
    
    $fp = @fsockopen($url[host], 80, $errno, $errstr, 30);
    if($fp) {
      fputs($fp, "GET /{$url['path']}?{$url['query']} HTTP/1.0\n");
      fputs($fp, "Host: {$url['host']}\n\n");
      fputs($fp, "Connection: close\n\n");
      fclose($fp);
    }
  } // end updateWpUserRoles($aRoles)
  
} // End of odWpPlugin

endif;
#}}} --- odWpPlugin


#{{{ odWpPlugin_Admin_Renderer ---
if(!class_exists('odWpPlugin_Admin_Renderer')):
#!odWpPlugin_Admin_Renderer##
endif;
#}}} --- odWpPlugin_Admin_Renderer


#{{{ odWpPlugin_Admin_Table ---
if(!class_exists('odWpPlugin_Admin_Table')):
#!odWpPlugin_Admin_Table##
endif;
#}}} --- odWpPlugin_Admin_Table


#{{{ odWpPlugin_Form_Interface ---
if(!interface_exists('odWpPlugin_Form_Interface')):
#!odWpPlugin_Form_Interface##
endif;
#}}} --- odWpPlugin_Form_Interface


#{{{ odWpPlugin_Form_Abstract ---
if(!class_exists('odWpPlugin_Form_Abstract')):
#!odWpPlugin_Form_Abstract##
endif;
#}}} --- odWpPlugin_Form_Abstract


#{{{ odWpPlugin_Form ---
if(!class_exists('odWpPlugin_Form')):
#!odWpPlugin_Form##
endif;
#}}} --- odWpPlugin_Form


#{{{ odWpPlugin_Model_Interface ---
if(!interface_exists('odWpPlugin_Model_Interface')):
#!odWpPlugin_Model_Interface##
endif;
#}}} --- odWpPlugin_Model_Interface


#{{{ odWpPlugin_Model_WithTrash_Interface ---
if(!interface_exists('odWpPlugin_Model_WithTrash_Interface')):
#!odWpPlugin_ModelWithTrash_Interface##
endif;
#}}} --- odWpPlugin_Model_WithTrash_Interface


#{{{ odWpPlugin_Model_WithVisibility_Interface ---
if(!interface_exists('odWpPlugin_Model_WithVisibility_Interface')):
#!odWpPlugin_ModelWithVisibility_Interface##
endif;
#}}} --- odWpPlugin_Model_WithVisibility_Interface


#{{{ odWpPlugin_Model_Simple ---
if(!class_exists('odWpPlugin_Model_Simple')):
#!odWpPlugin_Model_Simple##
endif;
#}}} --- odWpPlugin_Model_Simple


#{{{ odWpPlugin_Model_WithTrash ---
if(!class_exists('odWpPlugin_Model_WithTrash')):
#!odWpPlugin_Model_WithTrash##
endif;
#}}} --- odWpPlugin_Model_WithTrash


#{{{ odWpPlugin_Model_WithVisibility ---
if(!class_exists('odWpPlugin_Model_WithVisibility')):
#!odWpPlugin_Model_WithVisibility##
endif;
#}}} --- odWpPlugin_Model_WithVisibility


#{{{ odWpPlugin_Model_WithTrashAndVisibility ---
if(!class_exists('odWpPlugin_Model_WithTrashAndVisibility')):
#!odWpPlugin_Model_WithTrashAndVisibility##
endif;
#}}} --- odWpPlugin_Model_WithTrashAndVisibility


#{{{ odWpPlugin_Cli ---
if(!class_exists('odWpPlugin_Cli')):
#!odWpPlugin_Cli##
endif;
#}}} --- odWpPlugin_Cli
